package com.glsc.ngateway.platform.exception;

import com.alibaba.fastjson.JSONObject;
import com.glsc.ngateway.common.api.common.enums.DictConstant;
import com.glsc.ngateway.common.api.common.enums.RabbitExcQueConstant;
import com.glsc.ngateway.common.base.domain.mysql.gateway.other.Message;
import com.glsc.ngateway.common.base.dto.others.WechatMsgDto;
import com.glsc.ngateway.common.api.platform.resp.PlatformResponse;
import com.glsc.ngateway.common.base.exception.PlatformException;
import com.glsc.ngateway.common.base.repo.mysql.gateway.other.MessageRepository;
import com.glsc.ngateway.platform.service.MailService;
import com.glsc.ngateway.platform.service.SystemConfigService;
import com.glsc.ngateway.platform.utils.DateUtils;
import com.glsc.ngateway.platform.utils.RequestTool;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.IOException;
import java.util.Arrays;
import java.util.UUID;
import java.util.stream.Collectors;

@ControllerAdvice
public class WebExceptionHandler {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private MailService mailService;
    @Resource
    private SystemConfigService systemConfigService;
    @Resource
    private MessageRepository messageRepository;
    @Resource
    private AmqpTemplate rabbitTemplate;

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public <T extends RuntimeException> PlatformResponse<Void> IllegalArgumentExceptionHandler(T e) {
        logger.error("异常", e);
        //logger.error("抛出RuntimeException异常：" + e.getClass().getSimpleName() + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond));
        //logger.error("runtime异常", e);
        return PlatformResponse.failedMsg("操作失败", e.getMessage());
    }

    /**
     * 处理Get请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public <T extends BindException> PlatformResponse<Void> bindExceptionHandler(T e) {
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
        logger.error("异常", e);
        return PlatformResponse.failedMsg("操作失败", message);
    }

    /**
     * 处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是javax.validation.ConstraintViolationException
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public <T extends ConstraintViolationException> PlatformResponse<Void> constraintViolationExceptionHandler(T e) {
        String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
        logger.error("异常", e);
        return PlatformResponse.failedMsg("操作失败", message);
    }

    /**
     * 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public <T extends MethodArgumentNotValidException> PlatformResponse<Void> methodArgumentNotValidExceptionHandler(T e) {
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
        logger.error("异常", e);
        return PlatformResponse.failedMsg("操作失败", message);
    }

    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public <T extends RuntimeException> PlatformResponse<Void> runtimeExceptionHandler(T e) {
        logger.error("异常", e);
        logger.error("抛出RuntimeException异常：" + e.getClass().getSimpleName() + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond));
        logger.error("runtime异常", e);
        mailService.sendMailToAdmin("网关platform异常", e.getMessage() + "\r\n" + Arrays.toString(e.getStackTrace()));
        sendMessage("网关platform异常: " + e.getMessage());
        return PlatformResponse.failedMsg("操作失败", e.getMessage());
    }


    @ExceptionHandler(PlatformException.class)
    @ResponseBody
    public <T extends PlatformException> PlatformResponse<Void> platformExceptionHandler(T e) {
        String errMsg = Strings.isNotBlank(e.getMsg()) ? e.getMsg() : "操作失败";
        logger.error(String.format("抛出PlatformException异常：%s, 时间为：%s, 错误信息：%s", e.getClass().getSimpleName(), DateUtils.getCurrentDate(DateUtils.formatSecond), errMsg));
        if (e.isPrintStackTraceFlag()) {
            logger.error("异常", e);
        }
        if (e.isSendMail2Admin()) {
            mailService.sendMailToAdmin("网关platform异常", e.getMessage() + "\r\n" + Arrays.toString(e.getStackTrace()));
            sendMessage("网关platform异常: " + e.getMessage());
        }
        logger.error("异常", e);
        return PlatformResponse.failedMsg(errMsg, Strings.isNotBlank(e.getMsg()) ? e.getMsg() : e.getMessage());
    }

    /**
     * @param e
     * @Description 500异常处理
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public <T extends Exception> PlatformResponse<?> exceptionHandler(T e) {
        logger.error("异常", e);
        logger.error("抛出Exception异常：" + e.getClass().getSimpleName() + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond));
        logger.error("异常", e);
        if (e instanceof IOException && e.getMessage().contains("断开的管道")){
            //不发送报警邮件
        } else {
            mailService.sendMailToAdmin("网关platform异常", e.getMessage() + "\r\n" + Arrays.toString(e.getStackTrace()));
            sendMessage("网关platform异常: " + e.getMessage());
        }
        return PlatformResponse.failedMsg("操作失败", e.getMessage());
    }

    public void sendMessage(String msg) {
        String remindGroupName = systemConfigService.findConfigValueByCode("WEIXIN_GROUP_NAME_ADMIN_REMIND");
        if(Strings.isBlank(remindGroupName)){
            logger.error("微信通知失败，未找到配置：WEIXIN_GROUP_NAME_ADMIN_REMIND");
            return;
        }
        WechatMsgDto msgDto = WechatMsgDto.builder().group(remindGroupName).msgId(UUID.randomUUID().toString()).sysid("glgateway").msgtype("markdown").content(msg).build();
        String context = JSONObject.toJSONString(msgDto);
        logger.info("WorkFlowSender开始发送消息：context :  " + context);
        try {
            //保存消息至数据库
            Message message = new Message();
            message.setMsgType(DictConstant.MSG_TYPE_SYNC);
            message.setMsgContent(msg);
            message.setMsgStatus(DictConstant.MSG_STATUS_SUCCESS);
            message.setMsgSender(RequestTool.getLocalHost());
            message.setOpAction(DictConstant.OP_ACTION_ADD);
            message.setOpSource(DictConstant.OP_SOURCE_WEB);
            messageRepository.saveAndFlush(message);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        rabbitTemplate.convertAndSend(RabbitExcQueConstant.AMPRODUCT_EXCHANGE_WEIXING, RabbitExcQueConstant.AMPRODUCT_QUEUE_WECHAT_MSG, context);
    }
}